
package xib.core;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import xib.parserTools.data.HeaderData;
import xib.parserTools.interfaces.IAdapterParser;
import xib.utils.EncodedString;

/**
 *
 * @author xavierds
 */
final class Xib{

    /**
     * Attributes with the adaptee to load the information from the file.
     */
    private IAdapterParser adaptee;

    /**
     * Complete pathname of the file.
     */
    //private String pathname;

    /**
     * List of chapters present.
     */
    private ArrayList<ChapterXib> chapters;

    /**
     * Attribute to set if it was initialized.
     */
    private boolean initialize;

    /**
     * Attribute with the default height of the page.
     */
    private int defaultPageHeight;

    /**
     * Attribute with the default width of the page.
     */
    private int defaultPageWidth;

    /**
     * List of languages present.
     */
    private ArrayList<String> languages;

    /**
     * List of avalaibles languages.
     */
    private ArrayList<EncodedString> titles;

    /**
     * List of authors in all avalaibles languages.
     */
    private ArrayList<ArrayList<EncodedString>> authors;

    /**
     * List of chapters numbers and chapters pages.
     */
    private ArrayList<Integer> chaptersNumbers, chaptersPages;

    /**
     * Hash table with the chapters relative positions order by their numbers
     */
    private Hashtable<Integer, Integer> chaptersPositions;

    /**
     * Attribute with the total of pages.
     */
    private int totalPages, totalPanels;

    private String originalLanguage, defaultLanguage;

    /**
     * Constructor by default, set the adaptee to use in the XIB.
     * @param adaptee
     */
    public Xib(IAdapterParser adaptee){
        if(adaptee == null)
            throw new NullPointerException("The adaptee wasn't initialized" +
                    "properly");
        this.adaptee = adaptee;
        initialize = false;
    }

    /**
     * Load the file into the xib. For this the adaptee is going to process
     * the file selected by the pathname.
     * @param pathname
     */
    public void loadInputStream(InputStream input)throws IOException{
        
        //Initialize the values for the Xib
        totalPages = 0;
        languages = new ArrayList<String>();
        titles = new ArrayList<EncodedString>();
        chaptersNumbers = new ArrayList<Integer>();
        chaptersPositions = new Hashtable<Integer, Integer>();
        chaptersPages = new ArrayList<Integer>();

        //Initialize the adaptee with the file from the pathname.
        //this.pathname = pathname;
        chapters = new ArrayList<ChapterXib>();
        
        adaptee.loadInputStream(input);


        //Load the header information
        HeaderData header = (HeaderData) adaptee.getHeader();
        header.validate();
        defaultPageHeight = header.getDefaultPageHeight();
        defaultPageWidth = header.getDefaultPageWidth();
        languages = header.getAvailablesLanguages();
        titles = header.getTitles();
        authors = header.getAuthors();
        defaultLanguage = header.getDefaultLanguage();
        originalLanguage = header.getOriginalLanguage();

        //Load the chapter
        ChapterXib chapter;
        for(int i=0; i < adaptee.getChapters().size(); i++){
            chapter = new ChapterXib(adaptee.getChapters().get(i));
            totalPages += chapter.getTotalPages();
            totalPanels += chapter.getTotalPanels();
            chaptersNumbers.add(chapter.getNumber());
            chaptersPages.add(chapter.getTotalPages());
            chaptersPositions.put(chapter.getNumber(), i);
            chapters.add(chapter);
        }

        initialize = true;
    }


    /**
     * Obtain the total of pages present in the file.
     * @return
     */
    public int getTotalPages(){
        notInitialized();
        return totalPages;
    }

    public int getTotalPanels(){
        notInitialized();
        return totalPanels;
    }

    public int getTotalPagesOfChapter(int chapterNumber){
        notInitialized();
        Integer pos = chaptersPositions.get(chapterNumber);
        if(pos == null)
            throw new IllegalArgumentException("This chapter number doesn't " +
                    "exist in the core.");
        return chaptersPages.get(pos);
    }

    /**
     * Obtain the list of chapters numbers.
     * @return
     */
    public ArrayList<Integer> getChaptersNumbers(){
        notInitialized();
        return chaptersNumbers;
    }

    public ArrayList<String> getAvailablesLanguages(){
        notInitialized();
        return languages;
    }

    public String getOriginalLanguage(){
        return originalLanguage;
    }

    public String getDefaultLanguage(){
        return defaultLanguage;
    }

    /**
     * Obtain the page x from the chapter y.
     * @param chapter
     * @param page
     * @return
     */
    public PageXib getPageAt(int chapter, int page){
        notInitialized();
        Integer pos = chaptersPositions.get(chapter);
        if(pos == null)
            throw new IllegalArgumentException("This chapter number doesn't " +
                    "exist in the core.");
        return chapters.get(pos).getPageAt(page);
    }

    /**
     * Obtain the page x
     * @param page
     * @return
     */
    public PageXib getPageAt(int page){
        notInitialized();
        if(page < 1 || page > totalPages)
            throw new IllegalArgumentException("Page must be between" +
                    "1 and  " + totalPages);
        int location[] = foundChapterAsPage(page);
        return chapters.get(location[0]).getPageAt(location[1]);
    }


    //TODO -> document getPanelAt
    public PanelXib getPanelAt(int page, int panel){
        notInitialized();
        return (PanelXib) getPageAt(page).getPanel(panel);
    }

    //TODO -> document getPanelAt
    public PanelXib getPanelAt(int chapter, int page, int panel){
        notInitialized();
        return (PanelXib) getPageAt(chapter, page).getPanel(panel);
    }

    
    int[] foundChapterAsPage(int page){
        notInitialized();
        int i;
        int[] res = new int[2];
        
        boolean notFound = true;

        i = 0;
        while(notFound){
            if(page <= chaptersPages.get(i))
                notFound = false;
            else{
                page -= chaptersPages.get(i);
                i++;
            }
        }
        res[0] = i;
        res[1] = page;

        return res;
    }

    private void notInitialized(){
        if(!initialize)
            throw new IllegalStateException("No file loaded");
    }
    
}
